using System;
using System.Collections.Generic;

namespace Aks.Deployment.SharePoint.Data
{
	/// <summary>
	/// Represents a CAML where node.
	/// </summary>
	internal class CamlWhereClause : CamlNode
	{
		/// <summary>CAML where clause. Arguments include: (0) XML comparisons.</summary>
		private const string CamlFormat = @"<Where>{0}</Where>";


		/// <summary>
		/// Initializes a new instance of the <see cref="CamlWhereClause"/> class.
		/// </summary>
		public CamlWhereClause()
		{}


		/// <summary>
		/// Initializes a new instance of the <see cref="CamlWhereClause"/> class.
		/// </summary>
		/// <param name="condition">The condition.</param>
		public CamlWhereClause(CamlComparison condition)
		{
			Condition = condition;
		}


		/// <summary>
		/// Gets or sets the condition.
		/// </summary>
		/// <value>The condition.</value>
		public CamlComparison Condition { get; set; }


		/// <summary>
		/// Returns a string that represents the current CAML node.
		/// </summary>
		/// <returns>A string representation of the CAML node.</returns>
		public override string ToCaml()
		{
			return (Condition == null) ? null : String.Format(CamlFormat, Condition.ToCaml());
		}


		#region | Field = (value) |

		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is equal to the specified <paramref name="value"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="value">The value.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldEqualToValue(string field, bool value)
		{
			return new CamlWhereClause(CamlComparison.FieldEqualToValue(field, value)).ToCaml();
		}


		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is equal to the specified <paramref name="value"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="value">The value.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldEqualToValue(string field, int value)
		{
			return new CamlWhereClause(CamlComparison.FieldEqualToValue(field, value)).ToCaml();
		}


		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is equal to the specified <paramref name="value"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="value">The value.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldEqualToValue(string field, string value)
		{
			return new CamlWhereClause(CamlComparison.FieldEqualToValue(field, value)).ToCaml();
		}


		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is equal to the specified choice <paramref name="value"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="value">The value.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldEqualToChoiceValue(string field, string value)
		{
			return new CamlWhereClause(CamlComparison.FieldEqualToChoiceValue(field, value)).ToCaml();
		}


		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is equal to the specified choice <paramref name="value"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="userName">Name of the user.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldEqualToUserName(string field, string userName)
		{
			return new CamlWhereClause(CamlComparison.FieldEqualToUserName(field, userName)).ToCaml();
		}

		#endregion


		#region | Field != (value) |

		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is equal to the specified <paramref name="value"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="value">The value.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldNotEqualToValue(string field, string value)
		{
			return new CamlWhereClause(CamlComparison.FieldNotEqualToValue(field, value)).ToCaml();
		}


		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is equal to the specified choice <paramref name="value"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="value">The value.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldNotEqualToLookupValue(string field, string value)
		{
			return new CamlWhereClause(CamlComparison.FieldNotEqualToLookupValue(field, value)).ToCaml();
		}

		#endregion


		#region | Field in (values) |

		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is in the specified array of <paramref name="values"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="values">The values.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldInValues(string field, params int[] values)
		{
			var camlValues = new List<CamlValue<int>>();
			for (var i = 0; i < values.Length; i++)
			{
				camlValues.Add(new CamlIntValue(values[i]));
			}
			return FieldInValues(field, camlValues.ToArray());
		}


		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is in the specified array of <paramref name="values"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="values">The values.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		public static string FieldInValues(string field, params string[] values)
		{
			var camlValues = new List<CamlValue<string>>();
			for (var i = 0; i < values.Length; i++)
			{
				camlValues.Add(new CamlTextValue(values[i]));
			}
			return FieldInValues(field, camlValues.ToArray());
		}


		/// <summary>
		/// Returns a string that represents a CAML query where the <paramref name="field"/> is in the specified array of <paramref name="values"/>.
		/// </summary>
		/// <param name="field">The field.</param>
		/// <param name="values">The values.</param>
		/// <returns>A string representation of the CAML where clause.</returns>
		private static string FieldInValues<T>(string field, CamlValue<T>[] values)
		{
			// validate params
			if (String.IsNullOrEmpty(field) || values == null || values.Length == 0)
				return null;

			// get conditions
			var camlField = new CamlField(field);
			var where = new CamlWhereClause();
			for (var i = 0; i < values.Length; i++)
			{
				var comparison = new CamlComparison(camlField, CamlComparisonType.EqualTo, values[i]);
				where.Condition = (i == 0) ? comparison : new CamlComparison(where.Condition, CamlComparisonType.Or, comparison);
			}

			// return
			return where.ToCaml();
		}

		#endregion
	}
}